
#include "ADebug.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "AObject.h"
#include "platform/CCFileUtils.h"

static const char* _level2str(ELogLevel level)
{
	switch (level)
	{
	case LL_Error: 	return "error: ";
	case LL_Warning:return "warn : ";
	case LL_Info:   return "info : ";
	case LL_Debug:	return "debug: ";
	}
	return "unknown: ";
}

/*
#if defined(WIN32)
#include "windows.h"
#pragma comment(lib, "winmm.lib") 
int gettimeofday(struct timeval* tp, void* tzp) {
	DWORD t;
	t = timeGetTime();
	tp->tv_sec = t / 1000;
	tp->tv_usec = t % 1000;
	//0 indicates that the call succeeded.
	return 0;
}
#endif //WIN32
*/

static const char* _getTimeString(char* szName, bool bForFile)
{
	time_t timep;

	time(&timep);

	struct tm* t = localtime(&timep);

	struct timeval tv;
	gettimeofday(&tv, NULL);

    if (bForFile)
    {
		sprintf(szName, "%04d-%02d-%02d", t->tm_year, t->tm_mon + 1, t->tm_mday);
    }
	else
	{
		sprintf(szName, /*"%04d-"*/"%02d-%02d %02d:%02d:%02d:%03d - "/*, t->tm_year*/,
            t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (int)(tv.tv_usec / 1000));
	}

    return szName;
}

class _FileDescriptorHolder
{
protected:
	FILE* _fp;
	bool _inited;
	void _init()
	{
		if (_inited)
			return;

		CAString path = CCFileUtils::getWriteablePath();
		try
		{
			char szLogFile[512];
			char szTemp[64];
			sprintf(szLogFile, "%s%s%s.log", path.c_str(), "ca_log_", _getTimeString(szTemp, true));
			//fprintf(stdout, "\n\n\n\ninitialize log file\n");
			_fp = fopen(szLogFile, "a+");
			if (NULL == _fp) 
			{
				//fprintf(stdout, "can not open log file, create it\n");
				_fp = fopen(szLogFile, "wb");
			}
			if (NULL == _fp)
			{
				//fprintf(stdout, "open log file failed:%s\n", szLogFile);
			}
		}
		catch (...)
		{
			//fprintf(stderr, exception.what());
		}

		_inited = true;
	}
public:
	_FileDescriptorHolder() 
	{ 
		_fp = NULL; 
		_inited = false;
	}
	~_FileDescriptorHolder()
	{
		if (NULL != _fp)
		{
			fclose(_fp);
		}
	}

	void writeLine(const char* szLine)
	{
		if (!_inited) _init();
		if (NULL == _fp)
		{
			return;
		}
		fwrite(szLine, 1, strlen(szLine), _fp);
		fflush(_fp);
		//CCLOGINFO(szLine);
		//fwrite(szLine, 1, strlen(szLine), stdout);
	}

	void writeLine(const char* fmt, va_list ap)
	{
		if (!_inited) _init();
		if (NULL == _fp)
			return;
		char sz[4096];
		vsprintf(sz, fmt, ap);
		writeLine(sz);
		//vfprintf(stdout, fmt, ap);
	}
};

static _FileDescriptorHolder _fdHolder;

#if defined(_DEBUG)
	ELogLevel CADebug::_log_level = LL_Debug;
#else
	ELogLevel CADebug::_log_level = LL_Error;
#endif

void CADebug::setTraceLevel(ELogLevel l)
{
	if (l > LL_Debug) l = LL_Debug;
	else if (l < LL_Error) l = LL_Error;
	_log_level = l;
}

void CADebug::Assert(const char* pszCondition, const char* pszFile, const char* pszFunction, int line)
{
	Error("assert failed, condition:[%s] function:[%s] at line:[%d] in file:[%s]\n",
		pszCondition, pszFunction, line, pszFile);
#if defined(WIN32)
	_asm int 3;
#endif
	//exit(1);
}

void CADebug::_trace(ELogLevel level, const char* fmt, va_list vlist)
{
	if (level > _log_level)
		return;

	char szBuff[2048];
	char szTemp[1024];
	szBuff[0] = 0;

	strcat(szBuff, _getTimeString(szTemp, 0));
	strcat(szBuff, _level2str(level));
	vsprintf(szBuff + strlen(szBuff), fmt, vlist);
	CCLOGINFO(szBuff);
	strcat(szBuff, "\n");

	_fdHolder.writeLine(szBuff);
}

void CADebug::Error(const char* fmt, ...)
{
	va_list ap;
	va_start (ap, fmt);
	_trace(LL_Error, fmt, ap);
	va_end (ap);
}

void CADebug::Warning(const char* fmt, ...)
{
	va_list ap;
	va_start (ap, fmt);
	_trace(LL_Warning, fmt, ap);
	va_end (ap);
}

void CADebug::Info(const char* fmt, ...)
{
	va_list ap;
	va_start (ap, fmt);
	_trace(LL_Info, fmt, ap);
	va_end (ap);
}

void CADebug::Debug(const char* fmt, ...)
{
	va_list ap;
	va_start (ap, fmt);
	_trace(LL_Debug, fmt, ap);
	va_end (ap);
}
